//
//  FeatActions.m
//  This file is part of D&D Manager
//
//  Created by Matthew Hutton on 25/02/2007.
//
//
//D&D Manager, a D&D Character and battle management program.
//Copyright (C) 2007, Matthew Hutton
//
//This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License along with this program; if not, write to:
//The Free Software Foundation, Inc.,
//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#import "FeatActions.h"
#import "AbilityChanged.h"
#import "AppController.h"

@implementation FeatActions
+(void)activateInCodeTheFeat:(NSManagedObject *)feat
			   nowShouldBeOn:(BOOL)on{
	if(on){
		//NSLog(@"activating the feat %@ belonging to %@",[feat valueForKey:@"name"],[[feat valueForKey:@"character"] valueForKey:@"name"]);
	}else{
		//NSLog(@"deactivating the feat %@ belonging to %@",[feat valueForKey:@"name"],[[feat valueForKey:@"character"] valueForKey:@"name"]);
	}
	NSArray *objects;
	if([[feat valueForKey:@"featAffects"] intValue]==1){
		objects=[[feat valueForKey:@"target"] allObjects];
	}else{
		objects=[NSArray arrayWithObject:[feat valueForKey:@"character"]];
	}
	int i;
	for(i=0;i<[objects count];i++){
		NSManagedObject *obj=[objects objectAtIndex:i];
		if(on){//button on.
			   //NSLog(@"active button going on.");
			[feat setValue:[NSNumber numberWithBool:YES]
					forKey:@"active"];
			if([[feat valueForKey:@"type"] intValue]==1){
				[self processFeat:feat
						 forKeyNo:1
						   onChar:obj
						 forwards:YES];
				[self processFeat:feat
						 forKeyNo:2
						   onChar:obj
						 forwards:YES];
				[self processFeat:feat
						 forKeyNo:3
						   onChar:obj
						 forwards:YES];
				[self processFeat:feat
						 forKeyNo:4
						   onChar:obj
						 forwards:YES];
			}else if([[feat valueForKey:@"type"] intValue]==0){
				//process weapons.
				//NSLog(@"weapons on");
				[self processFeat:feat
						 forKeyNo:1
						onWeapons:[[obj valueForKey:@"weapons"] allObjects]
						 forwards:YES];
				[self processFeat:feat
						 forKeyNo:2
						onWeapons:[[obj valueForKey:@"weapons"] allObjects]
						 forwards:YES];
				
			}
		}else{//button now off.
			  //NSLog(@"active button going off.");
			if([[feat valueForKey:@"type"] intValue]==1){
				//NSLog(@"character feat");
				[self processFeat:feat
						 forKeyNo:1
						   onChar:obj
						 forwards:NO];
				[self processFeat:feat
						 forKeyNo:2
						   onChar:obj
						 forwards:NO];
				[self processFeat:feat
						 forKeyNo:3
						   onChar:obj
						 forwards:NO];
				[self processFeat:feat
						 forKeyNo:4
						   onChar:obj
						 forwards:NO];
			}else if([[feat valueForKey:@"type"] intValue]==0){
				//process weapons.
				//NSLog(@"weapons on");
				[self processFeat:feat
						 forKeyNo:1
						onWeapons:[[obj valueForKey:@"weapons"] allObjects]
						 forwards:NO];
				[self processFeat:feat
						 forKeyNo:2
						onWeapons:[[obj valueForKey:@"weapons"] allObjects]
						 forwards:NO];
				
			}
			[feat setValue:[NSNumber numberWithBool:NO]
					forKey:@"active"];
		}
	}
}
+(int)checkFeat:(NSManagedObject *)feat
		 forKey:(NSString *)key{
	if([[feat valueForKey:@"key1"] isEqualToString:key] ||[[feat valueForKey:@"weapKey1"] isEqualToString:key]||[[feat valueForKey:@"spellKey"] isEqualToString:key]){
		return 1;
	}else if([[feat valueForKey:@"key2"] isEqualToString:key] || [[feat valueForKey:@"weapKey2"] isEqualToString:key]){
		return 2;
	}else if([[feat valueForKey:@"key3"] isEqualToString:key]){
		return 3;
	}else if([[feat valueForKey:@"key4"] isEqualToString:key]){
		return 4;
	}
	return 0;
}
+(void)setupFeatsForCaster:(NSManagedObject *)obj
				 forTarget:(NSManagedObject *)obj2
				   atRange:(int)range
					 nowOn:(BOOL)nowOn{
	NSArray *feats=[[obj valueForKey:@"feats"] allObjects];
	int i;
	for(i=0;i<[feats count];i++){
		NSManagedObject *feat=[feats objectAtIndex:i];
		if(![[feat valueForKey:@"active"] boolValue] || ![[feat valueForKey:@"target"] containsObject:obj2]){
			continue;
		}
		int res=[self checkFilterForFeat:feat
						   withCharacter:obj2];
		if(res!=0 && [self targetedFeatShouldActivate:feat
											  forRange:range]){
			[self activateInCodeTheFeat:feat
						  nowShouldBeOn:nowOn];
			[feat setValue:[NSNumber numberWithBool:YES]
					forKey:@"active"];
		}
	}
	feats=[[obj2 valueForKey:@"feats"] allObjects];
	for(i=0;i<[feats count];i++){
		NSManagedObject *feat=[feats objectAtIndex:i];
		if(![[feat valueForKey:@"active"] boolValue] || ![[feat valueForKey:@"target"] containsObject:obj]){
			continue;
		}
		int res=[self checkFilterForFeat:feat
						   withCharacter:obj];
		if(res!=0 && [self targetedFeatShouldActivate:feat
											 forRange:range]){
			[self activateInCodeTheFeat:feat
						  nowShouldBeOn:nowOn];
			[feat setValue:[NSNumber numberWithBool:YES]
					forKey:@"active"];
		}
	}
}
+(int)checkFilterForFeat:(NSManagedObject *)feat
		   withCharacter:(NSManagedObject *)obj{
	NSString *ff=[feat valueForKey:@"featFilter"];
	if([ff isEqualToString:@"All"]){
		return 2;
	}else if([ff isEqualToString:@"Good"]){
		return [AbilityChanged isGood:obj];
	}else if([ff isEqualToString:@"Evil"]){
		return [AbilityChanged isEvil:obj];
	}else if([ff isEqualToString:@"Lawful"]){
		return [AbilityChanged isLawful:obj];
	}else if([ff isEqualToString:@"Chaotic"]){
		return [AbilityChanged isChaotic:obj];
	}else{
		if([[obj valueForKey:@"type"] isEqualToString:ff]){
			return 1;
		}
		return 0;
	}
	return 0;
}

+(void)processFeat:(NSManagedObject *)feat
		  forKeyNo:(int)no
		 onWeapons:(NSArray *)weapons
		  forwards:(BOOL)f{
	if(![[feat valueForKey:@"active"] boolValue]){
		return;
	}
	NSString *mod=[feat valueForKey:[NSString stringWithFormat:@"weapMod%d",no]];
	NSString *key=[feat valueForKey:[NSString stringWithFormat:@"weapKey%d",no]];
	//now check if mod a +x or -x and change the mod string as required.
	if([mod isEqualToString:@"+x"]){
		mod=[NSString stringWithFormat:@"+%d",[[feat valueForKey:@"xValue"] intValue]];
	}else if([mod isEqualToString:@"-x"]){
		mod=[NSString stringWithFormat:@"-%d",[[feat valueForKey:@"xValue"] intValue]];
	}
	int i;
	//check the weapon type affected.
	if([[feat valueForKey:@"weaponTypeAffected"] intValue]==0){
		if([weapons containsObject:[feat valueForKey:@"weapon"]]){
			weapons=[NSArray arrayWithObject:[feat valueForKey:@"weapon"]];
		}else{
			weapons=nil;
		}
	}else if([[feat valueForKey:@"weaponTypeAffected"] intValue]==1){
		weapons=[weapons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"weaponType==2"]];
	}else if([[feat valueForKey:@"weaponTypeAffected"] intValue]==2){
		weapons=[weapons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"weaponType==0"]];
	}else if([[feat valueForKey:@"weaponTypeAffected"] intValue]==3){
		//no effect as just does all weapons given.
	}
	if(f){
		for(i=0;i<[weapons count];i++){
			NSManagedObject *weap=[weapons objectAtIndex:i];
			if([key isEqualToString:@"Critical Threat"]){
				int oldValue=[[weap valueForKey:@"minRollForCritical"] intValue];
				int set=20-oldValue+1;
				int newValue=20-[self processValue:set
										byModifier:mod]+1;
				[weap setValue:[NSNumber numberWithInt:newValue]
						forKey:@"minRollForCritical"];
			}else if([key isEqualToString:@"Range Increment (x10)"]){
				int value=[[weap valueForKey:@"rangeIncrement"] intValue];
				value=[self processValue:value
							  byModifier:mod]*10;
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"rangeIncrement"];
			}else if([key isEqualToString:@"Damage"]){
				int value=[[weap valueForKey:@"fixedBonusDamage"] intValue];
				value=[self processValue:value
							  byModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"fixedBonusDamage"];
			}else if([key isEqualToString:@"Attack Bonus"]){
				int value=[[weap valueForKey:@"weaponAttackBonus"] intValue];
				value=[self processValue:value
							  byModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"weaponAttackBonus"];
			}else if([key isEqualToString:@"Extra Attacks"]){
				int value=[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue];
				value=[self processValue:value
							  byModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"noOfSimultaneousAttacks"];
			}
		}
		if(![weapons count]>0){
			return;
		}
		NSManagedObject *obj=[[weapons objectAtIndex:0] valueForKey:@"character"];
		if([key isEqualToString:@"TW Main Penalty"]){
			int value=[[obj valueForKey:@"mainHandPenalty"] intValue];
			value=[self processValue:value
						  byModifier:mod];
			[obj setValue:[NSNumber numberWithInt:value]
				   forKey:@"mainHandPenalty"];
		}else if([key isEqualToString:@"TW Off Penalty"]){
			int value=[[obj valueForKey:@"offHandPenalty"] intValue];
			value=[self processValue:value
						  byModifier:mod];
			[obj setValue:[NSNumber numberWithInt:value]
				   forKey:@"offHandPenalty"];
		}
	}else{
		for(i=0;i<[weapons count];i++){
			NSManagedObject *weap=[weapons objectAtIndex:i];
			if([key isEqualToString:@"Critical Threat"]){
				int oldValue=[[weap valueForKey:@"minRollForCritical"] intValue];
				int set=20-oldValue+1;
				int newValue=20-[self processValue:set
							   byReverseOfModifier:mod]+1;
				[weap setValue:[NSNumber numberWithInt:newValue]
						forKey:@"minRollForCritical"];
			}else if([key isEqualToString:@"Range Increment"]){
				int value=[[weap valueForKey:@"rangeIncrement"] intValue];
				value=[self processValue:value
					 byReverseOfModifier:mod]*10;
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"rangeIncrement"];
			}else if([key isEqualToString:@"Attack Bonus"]){
				int value=[[weap valueForKey:@"weaponAttackBonus"] intValue];
				value=[self processValue:value
					 byReverseOfModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"weaponAttackBonus"];
			}else if([key isEqualToString:@"Damage"]){
				int value=[[weap valueForKey:@"fixedBonusDamage"] intValue];
				value=[self processValue:value
					 byReverseOfModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"fixedBonusDamage"];
			}else if([key isEqualToString:@"Extra Attacks"]){
				int value=[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue];
				value=[self processValue:value
							  byReverseOfModifier:mod];
				[weap setValue:[NSNumber numberWithInt:value]
						forKey:@"noOfSimultaneousAttacks"];
			}
		}
		if(![weapons count]>0){
			return;
		}
		NSManagedObject *obj=[[weapons objectAtIndex:0] valueForKey:@"character"];
		if([key isEqualToString:@"TW Main Penalty"]){
			int value=[[obj valueForKey:@"mainHandPenalty"] intValue];
			value=[self processValue:value
				 byReverseOfModifier:mod];
			[obj setValue:[NSNumber numberWithInt:value]
				   forKey:@"mainHandPenalty"];
		}else if([key isEqualToString:@"TW Off Penalty"]){
			int value=[[obj valueForKey:@"offHandPenalty"] intValue];
			value=[self processValue:value
				 byReverseOfModifier:mod];
			[obj setValue:[NSNumber numberWithInt:value]
				   forKey:@"offHandPenalty"];
		}
	}
}
+(void)processFeat:(NSManagedObject *)feat
		  forKeyNo:(int)no
			onChar:(NSManagedObject *)obj
		  forwards:(BOOL)f{
	if(![[feat valueForKey:@"active"] boolValue]){
		return;
	}
	NSString *mod=[feat valueForKey:[NSString stringWithFormat:@"mod%d",no]];
	NSString *key=[feat valueForKey:[NSString stringWithFormat:@"key%d",no]];
	int modAsInt=0;
	//check if spell then do a dice roll, or get "x" value if a feat.
	NSManagedObjectContext *mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
	//NSLog(@"context found");
	NSManagedObjectModel *model=[[mObjC persistentStoreCoordinator] managedObjectModel];
	if([[feat entity] isEqualTo:[[model entitiesByName]  objectForKey:@"NewSpell"]]){
		NSString *dieMod=[feat valueForKey:[NSString stringWithFormat:@"dieMod%d",no]];
		if(f){
			if([dieMod isEqualToString:@"1d2"]){
				modAsInt=[RandomNumbers randomIntUpTo:2];
			}else if([dieMod isEqualToString:@"1d3"]){
				modAsInt=[RandomNumbers randomIntUpTo:3];
			}else if([dieMod isEqualToString:@"1d4"]){
				modAsInt=[RandomNumbers randomIntUpTo:4];
			}else if([dieMod isEqualToString:@"1d6"]){
				modAsInt=[RandomNumbers randomIntUpTo:6];
			}else if([dieMod isEqualToString:@"1d8"]){
				modAsInt=[RandomNumbers randomIntUpTo:8];
			}else if([dieMod isEqualToString:@"1d10"]){
				modAsInt=[RandomNumbers randomIntUpTo:10];
			}
			[feat setValue:[NSNumber numberWithInt:modAsInt]
					forKey:[NSString stringWithFormat:@"dieRoll%d",no]];
		}else{
			modAsInt=[[feat valueForKey:[NSString stringWithFormat:@"dieRoll%d",no]] intValue];
		}
	}else{
		//now check for "x" value changes.
		if([mod isEqualToString:@"+x"]){
			modAsInt=[[feat valueForKey:@"xValue"] intValue];
		}
		if([mod isEqualToString:@"-x"]){
			modAsInt=-[[feat valueForKey:@"xValue"] intValue];
		}
	}
	//now add "mod" value.
	modAsInt=[self processValue:modAsInt
					 byModifier:mod];
	[self processFeat:feat
			 forKeyNo:no
			  withKey:key
			  withMod:modAsInt
			   onChar:obj
			 forwards:f];
}
+(void)processFeat:(NSManagedObject *)feat
		  forKeyNo:(int)no
		   withKey:(NSString *)key
		   withMod:(int)mod
			onChar:(NSManagedObject *)obj
		  forwards:(BOOL)f{	
	//NSLog(@"key=%@, mod=%@",key,mod);
	//NSLog(@"feat processing");
	//NSLog(@"key=%@ mod=%@",key,mod);
	if(f){
		if([key isEqualToString:@"Strength"]){
			int x=[[obj valueForKey:@"strengthTemp"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"strengthTemp"];
			[AbilityChanged strengthChangedForChar:obj];
		}else if([key isEqualToString:@"Dexterity"]){
			int x=[[obj valueForKey:@"dexterityTemp"] intValue];
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"dexterityTemp"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Constitution"]){
			int x=[[obj valueForKey:@"constitutionTemp"] intValue]+mod;
			//get current/max HP.
			int currentHP=[[obj valueForKey:@"currentHP"] intValue];
			int maxHP=[[obj valueForKey:@"maxHP"] intValue];
			//set values
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"constitutionTemp"];
			[AbilityChanged constitutionChangedForChar:obj];
			//sort out current HP.
			int maxHP2=[[obj valueForKey:@"maxHP"] intValue];
			currentHP=currentHP+(maxHP2-maxHP);
			[obj setValue:[NSNumber numberWithInt:currentHP]
				   forKey:@"currentHP"];
			//for spell form only.
		}else if([key isEqualToString:@"Intelligence"]){
			int x=[[obj valueForKey:@"intelligenceTemp"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"intelligenceTemp"];
			[AbilityChanged intelligenceChangedForChar:obj];
		}else if([key isEqualToString:@"Wisdom"]){
			int x=[[obj valueForKey:@"wisdomTemp"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"wisdomTemp"];
			[AbilityChanged wisdomChangedForChar:obj];
		}else if([key isEqualToString:@"Charisma"]){
			int x=[[obj valueForKey:@"charismaTemp"] intValue]+mod;;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"charismaTemp"];
			[AbilityChanged charismaChangedForChar:obj];
		}else if([key isEqualToString:@"Hasted"]){
			[self enableHastedForChar:obj];
		}else if([key isEqualToString:@"Slowed"]){
			[self enableSlowedForChar:obj];
			//end of spell options.
		}else if([key isEqualToString:@"Attack Bonus"]){
			int x=[[obj valueForKey:@"rangedMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"rangedMiscBonus"];
			x=[[obj valueForKey:@"meleeMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"meleeMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Attack's of Opp"]){
			int x=[[obj valueForKey:@"maxAttackOO"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"maxAttackOO"];
		}else if([key isEqualToString:@"Initiative"]){
			//NSLog(@"hello!!");
			int x=[[obj valueForKey:@"initiativeMiscBonus"] intValue]+mod;
			//NSLog(@"x=%i",x);
			//NSLog(@"x=%i",x);
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"initiativeMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Hit Points"]){
			int x=[[obj valueForKey:@"maxHP"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"maxHP"];
			x=[[obj valueForKey:@"baseHP"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"baseHP"];
			x=[[obj valueForKey:@"currentHP"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"currentHP"];
		}else if([key isEqualToString:@"Armour Class"]){
			int x=[[obj valueForKey:@"armourClassDeflection"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"armourClassDeflection"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Reflex Save"]){
			int x=[[obj valueForKey:@"reflexMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"reflexMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Fortitude Save"]){
			int x=[[obj valueForKey:@"fortitudeMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"fortitudeMiscBonus"];
			[AbilityChanged constitutionChangedForChar:obj];
		}else if([key isEqualToString:@"Will Save"]){
			int x=[[obj valueForKey:@"willMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"willMiscBonus"];
			[AbilityChanged wisdomChangedForChar:obj];
		}else if([key isEqualToString:@"Turn's per Day"]){
			int x=[[obj valueForKey:@"tuMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"tuMiscBonus"];
			[AbilityChanged updateTurnUndeadForChar:obj];
		}else if([key isEqualToString:@"Turning Level"]){
			int x=[[obj valueForKey:@"tuCMiscBonus"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"tuCMiscBonus"];
			[AbilityChanged updateTurnUndeadForChar:obj];
		}else if([key isEqualToString:@"Arcane Spell Failure"]){
			int x=[[obj valueForKey:@"arcaneSpellFailure"] intValue]+mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"arcaneSpellFailure"];
		}else if([key isEqualToString:@"No Effect"] || [key isEqualToString:@"No Skill Chosen"]){
			//as nothing needs changing.
			//NSLog(@"no modifications");
		}else{
			//NSLog(@"skills");
			NSManagedObject *skill=[feat valueForKey:[NSString stringWithFormat:@"skill%d",no]];
			int miscMod=[[skill valueForKey:@"miscBonus"] intValue];
			int change=mod;
			[skill setValue:[NSNumber numberWithInt:miscMod+change]
					 forKey:@"miscBonus"];
			[skill setValue:[NSNumber numberWithInt:([[skill valueForKey:@"total"] intValue]+change)]
					 forKey:@"total"];
		}
	}else{
		//NSLog(@"feat going off (deactivating key)");
		if([key isEqualToString:@"Strength"]){
			int x=[[obj valueForKey:@"strengthTemp"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"strengthTemp"];
			[AbilityChanged strengthChangedForChar:obj];
		}else if([key isEqualToString:@"Dexterity"]){
			int x=[[obj valueForKey:@"dexterityTemp"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"dexterity"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Constitution"]){
			int x=[[obj valueForKey:@"constitutionTemp"] intValue]-mod;
			//get current/max HP.
			int currentHP=[[obj valueForKey:@"currentHP"] intValue];
			int maxHP=[[obj valueForKey:@"maxHP"] intValue];
			//set values
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"constitutionTemp"];
			[AbilityChanged constitutionChangedForChar:obj];
			//sort out current HP.
			int maxHP2=[[obj valueForKey:@"maxHP"] intValue];
			currentHP=currentHP+(maxHP2-maxHP);
			[obj setValue:[NSNumber numberWithInt:currentHP]
				   forKey:@"currentHP"];
			//for spell form only.
		}else if([key isEqualToString:@"Intelligence"]){
			int x=[[obj valueForKey:@"intelligenceTemp"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"intelligenceTemp"];
			[AbilityChanged intelligenceChangedForChar:obj];
		}else if([key isEqualToString:@"Wisdom"]){
			int x=[[obj valueForKey:@"wisdomTemp"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"wisdomTemp"];
			[AbilityChanged wisdomChangedForChar:obj];
		}else if([key isEqualToString:@"Charisma"]){
			int x=[[obj valueForKey:@"charismaTemp"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"charismaTemp"];
			[AbilityChanged charismaChangedForChar:obj];
		}else if([key isEqualToString:@"Hasted"]){
			[self disableHastedForChar:obj];
		}else if([key isEqualToString:@"Slowed"]){
			[self disableSlowedForChar:obj];
			//end of spell options.
		}else if([key isEqualToString:@"Attack Bonus"]){
			int x=[[obj valueForKey:@"rangedMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"rangedMiscBonus"];
			x=[[obj valueForKey:@"meleeMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"meleeMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Attack's of Opp"]){
			int x=[[obj valueForKey:@"maxAttackOO"] intValue]-mod;
			
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"maxAttackOO"];
		}else if([key isEqualToString:@"Initiative"]){
			int x=[[obj valueForKey:@"initiativeMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"initiativeMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Hit Points"]){
			int x=[[obj valueForKey:@"maxHP"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"maxHP"];
			x=[[obj valueForKey:@"baseHP"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"baseHP"];
			x=[[obj valueForKey:@"currentHP"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"currentHP"];
		}else if([key isEqualToString:@"Armour Class"]){
			int x=[[obj valueForKey:@"armourClassDeflection"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"armourClassDeflection"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Reflex Save"]){
			int x=[[obj valueForKey:@"reflexMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"reflexMiscBonus"];
			[AbilityChanged dexterityChangedForChar:obj];
		}else if([key isEqualToString:@"Fortitude Save"]){
			int x=[[obj valueForKey:@"fortitudeMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"fortitudeMiscBonus"];
			[AbilityChanged constitutionChangedForChar:obj];
		}else if([key isEqualToString:@"Will Save"]){
			int x=[[obj valueForKey:@"willMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"willMiscBonus"];
			[AbilityChanged wisdomChangedForChar:obj];
		}else if([key isEqualToString:@"Turn's per Day"]){
			int x=[[obj valueForKey:@"tuMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"tuMiscBonus"];
			[AbilityChanged updateTurnUndeadForChar:obj];
		}else if([key isEqualToString:@"Turning Level"]){
			int x=[[obj valueForKey:@"tuCMiscBonus"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"tuCMiscBonus"];
			[AbilityChanged updateTurnUndeadForChar:obj];
		}else if([key isEqualToString:@"Arcane Spell Failure"]){
			int x=[[obj valueForKey:@"arcaneSpellFailure"] intValue]-mod;
			[obj setValue:[NSNumber numberWithInt:x]
				   forKey:@"arcaneSpellFailure"];
		}else if([key isEqualToString:@"No Effect"] || [key isEqualToString:@"No Skill Chosen"]){
			//as nothing needs changing.
		}else{
			NSManagedObject *skill=[feat valueForKey:[[NSString alloc] initWithFormat:@"skill%d",no]];
			int miscMod=[[skill valueForKey:@"miscBonus"] intValue];
			int change=mod;
			[skill setValue:[NSNumber numberWithInt:miscMod-change]
					 forKey:@"miscBonus"];
			[skill setValue:[NSNumber numberWithInt:([[skill valueForKey:@"total"] intValue]-change)]
					 forKey:@"total"];
		}
	}
}
+(void)processFeat:(NSManagedObject *)feat
		  forKeyNo:(int)no
		   onSpell:(NSManagedObject *)spell
		  forwards:(BOOL)f{
	if(![[feat valueForKey:@"active"] boolValue]){
		return;
	}
	NSString *mod=[feat valueForKey:@"spellMod"];
	NSString *key=[feat valueForKey:@"spellKey"];
	if(f){
		//if([key isEqualToString:@"Range"]){
		//	int i=[[spell valueForKey:@"range"
		if([key isEqualToString:@"Duration"]){
			int i=[[spell valueForKey:@"lastsFor"] intValue];
			i=[self processValue:i
					  byModifier:mod];
			[spell setValue:[NSNumber numberWithInt:i]
					 forKey:@"lastsFor"];
		}
	}else{
		//if([key isEqualToString:@"Range"]){
		//	int i=[[spell valueForKey:@"range"
		if([key isEqualToString:@"Duration"]){
			int i=[[spell valueForKey:@"lastsFor"] intValue];
			i=[self processValue:i
			 byReverseOfModifier:mod];
			[spell setValue:[NSNumber numberWithInt:i]
					 forKey:@"lastsFor"];
		}
	}
}
 +(int)processValue:(int)value
 byReverseOfModifier:(NSString *)mod{
	 if([mod isEqualToString:@"+10"]){
		 value=value-10;
	 }else if([mod isEqualToString:@"+8"]){
		 value=value-8;
	 }else if([mod isEqualToString:@"+6"]){
		 value=value-6;
	 }else if([mod isEqualToString:@"+5"]){
		 value=value-5;
	 }else if([mod isEqualToString:@"+4"]){
		 value=value-4;
	 }else if([mod isEqualToString:@"+3"]){
		 value=value-3;
	 }else if([mod isEqualToString:@"+2"]){
		 value=value-2;
	 }else if([mod isEqualToString:@"+1"]){
		 value=value-1;
	 }else if([mod isEqualToString:@"+0"]){
		 value=value;
	 }else if([mod isEqualToString:@"-1"]){
		 value=value+1;
	 }else if([mod isEqualToString:@"-2"]){
		 value=value+2;
	 }else if([mod isEqualToString:@"-3"]){
		 value=value+3;
	 }else if([mod isEqualToString:@"-4"]){
		 value=value+4;
	 }else if([mod isEqualToString:@"-5"]){
		 value=value+5;
	 }else if([mod isEqualToString:@"x2"] || [mod isEqualToString:@"+100%%"]){
		 value=value/2;
	 }else if([mod isEqualToString:@"x1.5"] || [mod isEqualToString:@"+50%%"]){
		 value=(int)((double)value*0.666666666666667+0.5);
	 }else if([mod isEqualToString:@"x1.2"] || [mod isEqualToString:@"+20%%"]){
		 value=(int)((double)value*0.833333333333333+0.5);
	 }
	 return value;
 }
 +(int)processValue:(int)value
 byModifier:(NSString *)mod{
	if([mod isEqualToString:@"+10"]){
		value=value+10;
	}else if([mod isEqualToString:@"+8"]){
		value=value+8;
	}else if([mod isEqualToString:@"+6"]){
		value=value+6;
	}else if([mod isEqualToString:@"+5"]){
		value=value+5;
	}else if([mod isEqualToString:@"+4"]){
		value=value+4;
	}else if([mod isEqualToString:@"+3"]){
		value=value+3;
	}else if([mod isEqualToString:@"+2"]){
		value=value+2;
	}else if([mod isEqualToString:@"+1"]){
		value=value+1;
	}else if([mod isEqualToString:@"+0"]){
		value=value;
	}else if([mod isEqualToString:@"-1"]){
		value=value-1;
	}else if([mod isEqualToString:@"-2"]){
		value=value-2;
	}else if([mod isEqualToString:@"-3"]){
		value=value-3;
	}else if([mod isEqualToString:@"-4"]){
		value=value-4;
	}else if([mod isEqualToString:@"-5"]){
		value=value-5;
	}else if([mod isEqualToString:@"-6"]){
		value=value-6;
	}else if([mod isEqualToString:@"x2"] || [mod isEqualToString:@"+100%%"]){
		value=value*2;
	}else if([mod isEqualToString:@"x1.5"] || [mod isEqualToString:@"+50%%"]){
		value=(int)((double)value*1.5+0.5);
	}else if([mod isEqualToString:@"x1.2"] || [mod isEqualToString:@"+20%%"]){
		value=(int)((double)value*1.2+0.5);
	}
	 return value;
 }
+(void)enableHastedForChar:(NSManagedObject *)obj{
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"hasted"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"rangedMiscBonus"] intValue]+1]
		   forKey:@"rangedMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]+1]
		   forKey:@"meleeMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassDodge"] intValue]+1]
		   forKey:@"armourClassDodge"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"reflexMiscBonus"] intValue]+1]
		   forKey:@"reflexMiscBonus"];
	int m=[[obj valueForKey:@"speedModified"] intValue];
	if(m>30){
		m=m+30;
	}else{
		m=2*m;
	}
	[obj setValue:[NSNumber numberWithInt:m]
		   forKey:@"speedModified"];
	[AbilityChanged dexterityChangedForChar:obj];
	NSArray *weapons=[[obj valueForKey:@"weapons"] allObjects];
	int g;
	for(g=0;g<[weapons count];g++){
		[[weapons objectAtIndex:g] setValue:[NSNumber numberWithInt:[[[weapons objectAtIndex:g] valueForKey:@"noOfSimultaneousAttacks"] intValue]+1] forKey:@"noOfSimultaneousAttacks"];
	}
}
+(void)disableHastedForChar:(NSManagedObject *)obj{
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"hasted"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"rangedMiscBonus"] intValue]-1]
		   forKey:@"rangedMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]-1]
		   forKey:@"meleeMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassDodge"] intValue]-1]
		   forKey:@"armourClassDodge"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"reflexMiscBonus"] intValue]-1]
		   forKey:@"reflexMiscBonus"];
	int m=[[obj valueForKey:@"speedModified"] intValue];
	if(m>60){
		m=m-30;
	}else{
		m=m/2;
	}
	[obj setValue:[NSNumber numberWithInt:m]
		   forKey:@"speedModified"];
	[AbilityChanged dexterityChangedForChar:obj];
	//process weapons
	NSArray *weapons=[[obj valueForKey:@"weapons"] allObjects];
	int g;
	for(g=0;g<[weapons count];g++){
		[[weapons objectAtIndex:g] setValue:[NSNumber numberWithInt:[[[weapons objectAtIndex:g] valueForKey:@"noOfSimultaneousAttacks"] intValue]-1] forKey:@"noOfSimultaneousAttacks"];
	}
	
}
+(void)enableSlowedForChar:(NSManagedObject *)obj{
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"rangedMiscBonus"] intValue]-1]
		   forKey:@"rangedMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]-1]
		   forKey:@"meleeMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassDodge"] intValue]-1]
		   forKey:@"armourClassDodge"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"reflexMiscBonus"] intValue]-1]
		   forKey:@"reflexMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"speedModified"] intValue]/2)]
		   forKey:@"speedModified"];
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"slowed"];
	[AbilityChanged dexterityChangedForChar:obj];
}
+(void)disableSlowedForChar:(NSManagedObject *)obj{
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"rangedMiscBonus"] intValue]+1]
		   forKey:@"rangedMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]+1]
		   forKey:@"meleeMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassDodge"] intValue]+1]
		   forKey:@"armourClassDodge"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"reflexMiscBonus"] intValue]+1]
		   forKey:@"reflexMiscBonus"];
	int m=([[obj valueForKey:@"speedModified"] intValue]*2);
	//so rounds back up to 15,25,35 etc. etc.
	if(m%10==4){
		m++;
	}
	[obj setValue:[NSNumber numberWithInt:m]
		   forKey:@"speedModified"];			
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"slowed"];
	[AbilityChanged dexterityChangedForChar:obj];	
}
+(BOOL)featHasAMaxRange:(NSManagedObject *)feat{
	//NSLog(@"1");
	if([[feat valueForKey:@"type"] intValue]>0 || [[feat valueForKey:@"maxRange"] intValue]==0 || [[feat valueForKey:@"weaponTypeAffected"] intValue]%2==0){
		if([feat valueForKey:@"weapon"]!=nil){
			if([[feat valueForKey:@"weaponTypeAffected"] intValue]==0 && [[[feat valueForKey:@"weapon"] valueForKey:@"weaponType"] intValue]==0){
				return NO;
			}else{
				return YES;
			}
		}
		return NO;
	}else{
		return YES;
	} 
}
//out of combat should the feat activate.
+(BOOL)generallyFeatShouldActivate:(NSManagedObject *)feat{
	if(([[feat valueForKey:@"featAffects"] intValue]==0 && (![[feat valueForKey:@"ability"] boolValue] || [[feat valueForKey:@"featFilter"] isEqualToString:@"All"])) && ![self featHasAMaxRange:feat]){
		return YES;
	}else{
		return NO;
	}
}
//if we are starting combat any feats applied to targets can now be activated. (reverse when ending).
+(BOOL)startingCombatFeatShouldActivate:(NSManagedObject *)feat{
	if([[feat valueForKey:@"featAffects"] intValue]==1 && (![[feat valueForKey:@"ability"] boolValue] || [[feat valueForKey:@"featFilter"] isEqualToString:@"All"]) && ![self featHasAMaxRange:feat]){
		return YES;
	}else{
		return NO;
	}
	
}
//if the feat is being activated in combat it gets targets.
+(BOOL)inCombatFeatShouldActivate:(NSManagedObject *)feat{
	if([[feat valueForKey:@"featAffects"] intValue]!=2 && (![[feat valueForKey:@"ability"] boolValue] || [[feat valueForKey:@"featFilter"] isEqualToString:@"All"])  && ![self featHasAMaxRange:feat]){
		return YES;
	}else{
		return NO;
	}
}
//if the feat is already active then it returns no, otherwise yes.
+(BOOL)targetedFeatShouldActivate:(NSManagedObject *)feat
						 forRange:(int)range{
	if([[feat valueForKey:@"featAffects"] intValue]!=2 && (![[feat valueForKey:@"ability"] boolValue] || [[feat valueForKey:@"featFilter"] isEqualToString:@"All"])){
		if(range<=[[feat valueForKey:@"maxRange"] intValue] && [self featHasAMaxRange:feat]){
			return YES;
		}else{
			return NO;
		}
	}else{
		if(range>[[feat valueForKey:@"maxRange"] intValue] && [self featHasAMaxRange:feat]){
			return NO;
		}else{
			return YES;
		}
	}
}
+(BOOL)xValueInUse:(NSManagedObject *)feat{
	if([[feat valueForKey:@"type"] intValue]==0){
		if([[feat valueForKey:@"weapMod1"] hasSuffix:@"x"] || [[feat valueForKey:@"weapMod2"] hasSuffix:@"x"]){
			return YES;
		}else{
			return NO;
		}
	}else if([[feat valueForKey:@"type"] intValue]==1){
		if([[feat valueForKey:@"mod1"] hasSuffix:@"x"] || [[feat valueForKey:@"mod2"] hasSuffix:@"x"] || [[feat valueForKey:@"mod3"] hasSuffix:@"x"] || [[feat valueForKey:@"mod4"] hasSuffix:@"x"]){
			return YES;
		}else{
			return NO;
		}
	}else if([[feat valueForKey:@"type"] intValue]==2){
		if([[feat valueForKey:@"spellMod"] hasSuffix:@"x"]){
			return YES;
		}else{
			return NO;
		}
	}
	return NO;
}
+(BOOL)aMaxFeatSelectedForKey:(NSString *)key
					 forFeats:(NSArray *)feats{
	int i;
	for(i=0;i<[feats count];i++){
		NSManagedObject *feat=[feats objectAtIndex:i];
		NSString *spellMod=[feat valueForKey:@"spellMod"];
		if(![spellMod isEqualToString:@"Max"]){
			continue;//obviously can't be a Max feat ;).
		}
		if([self checkIfFeat:feat
				worksWithKey:key]){
			return YES;
		}
	}
	return NO;
}
+(BOOL)checkIfFeat:(NSManagedObject *)feat
	  worksWithKey:(NSString *)key{
	NSString *spellKey=[feat valueForKey:@"spellKey"];
	if([key isEqualToString:@"ran"] || [key isEqualToString:@"Range"]){
		if([spellKey isEqualToString:@"Range"] || [spellKey isEqualToString:@"Variable Effects"]){
			return YES;
		}
	}else if([key isEqualToString:@"noa"] || [key isEqualToString:@"No Of Attacks"]){
		if([spellKey isEqualToString:@"No Of Attacks"] || [spellKey isEqualToString:@"Variable Effects"]){
			return YES;
		}
	}else if([key isEqualToString:@"dur"] || [key isEqualToString:@"Duration"]){
		if([spellKey isEqualToString:@"Duration"] || [spellKey isEqualToString:@"Variable Effects"]){
			return YES;
		}
	}else if([key isEqualToString:@"dam"] || [key isEqualToString:@"Damage"]){
		if([spellKey isEqualToString:@"Damage"] || [spellKey isEqualToString:@"Variable Effects"]){
			return YES;
		}
	}
	return NO;
}
+(NSString *)modifyString:(NSString *)str
			 byMultiplier:(NSString *)mod{
	NSString *prefix;
	if([mod isEqualToString:@"x2"] || [mod isEqualToString:@"+100%%"]){
		prefix=@"2";
	}else if([mod isEqualToString:@"x1.5"] || [mod isEqualToString:@"+50%%"]){
		prefix=@"1.5";
	}else if([mod isEqualToString:@"x1.2"] || [mod isEqualToString:@"+20%%"]){
		prefix=@"1.2";
	}
	if([str rangeOfString:@"d"].location == NSNotFound){
		int val=[str intValue];
		val=(int)((double)val*[prefix doubleValue]+0.5);
		str=[NSString stringWithFormat:@"%d",val];
	}else{
		str=[NSString stringWithFormat:@"%@x(%@)",prefix,str];
	}
	return str;
}
@end
